package repositorys

import (
	"errors"
	"github.com/zhongshaofa/swan-jobs/internal/models"
	"github.com/zhongshaofa/swan-jobs/internal/plugin"
	"github.com/zhongshaofa/swan-jobs/internal/request"
	"gorm.io/gorm"
)

type ApplicationInterface interface {
	Detail(id int) (*models.Application, error)
	Create(m *models.Application) (*models.Application, error)
	Update(m *models.Application) error
	GetList(where *models.Application, pagination request.PaginationRequest) ([]*models.Application, int, error)
	Delete(ids []int) error
	SwitchStatus(ids []int, status int) error
	ClientAuth(appId int, clientIds []int) error
	ClientList(appId int) (*models.Application, error)
}

type ApplicationRepository struct {
}

func (ApplicationRepository) Detail(id int) (*models.Application, error) {
	m := models.Application{}
	result := plugin.DB.First(&m, id)
	if result.Error != nil {
		return nil, result.Error
	}
	return &m, nil
}

func (receiver ApplicationRepository) GetList(where *models.Application, pagination request.PaginationRequest) ([]*models.Application, int, error) {
	var list []*models.Application

	db := plugin.DB
	db = receiver.buildQuery(where, db).Limit(pagination.Limit).Offset((pagination.Page - 1) * pagination.Limit)
	result := db.Find(&list)

	if result.Error != nil {
		return nil, 0, result.Error
	}

	var count int64
	receiver.buildQuery(where, db).Count(&count)

	return list, int(count), nil
}

func (ApplicationRepository) Create(m *models.Application) (*models.Application, error) {
	var count int64
	plugin.DB.Model(&models.Application{}).Where("app_code = ?", m.AppCode).Count(&count)
	if count > 0 {
		return nil, errors.New("应用编码已存在")
	}

	result := plugin.DB.Create(&m)
	if result.Error != nil {
		return nil, result.Error
	}
	return m, nil
}

func (ApplicationRepository) Update(m *models.Application) error {
	var count int64
	plugin.DB.Model(&models.Application{}).
		Where("id <> ?", m.ID).
		Where("app_code = ?", m.AppCode).
		Count(&count)
	if count > 0 {
		return errors.New("应用编码已存在")
	}

	db := plugin.DB
	result := db.Save(&m)
	return result.Error
}

func (ApplicationRepository) Delete(ids []int) error {
	result := plugin.DB.Delete(&models.Application{}, ids)
	if result.Error != nil {
		return result.Error
	}
	return nil
}

func (receiver ApplicationRepository) SwitchStatus(ids []int, status int) error {
	result := plugin.DB.Model(&models.Application{}).
		Where("id in (?)", ids).
		Update("status", status)
	if result.Error != nil {
		return result.Error
	}
	return nil
}

func (receiver ApplicationRepository) ClientAuth(appId int, clientIds []int) error {
	var insertList []*models.ApplicationClient
	for _, clientId := range clientIds {
		insertList = append(insertList, &models.ApplicationClient{AppId: appId, ClientId: clientId})
	}
	err := plugin.DB.Transaction(func(tx *gorm.DB) error {
		if err := tx.Where("app_id = ?", appId).Delete(&models.ApplicationClient{}).Error; err != nil {
			return err
		}
		if err := tx.Create(&insertList).Error; err != nil {
			return err
		}
		return nil
	})
	return err
}

func (receiver ApplicationRepository) ClientList(appId int) (*models.Application, error) {
	application := models.Application{}
	result := plugin.DB.Preload("ClientList.Client").First(&application, appId)
	if result.Error != nil {
		return nil, result.Error
	}
	return &application, nil
}

func (ApplicationRepository) buildQuery(where *models.Application, db *gorm.DB) *gorm.DB {
	if len(where.AppName) > 0 {
		db = db.Where("app_name like ?", where.AppName+"%")
	}
	if len(where.AppCode) > 0 {
		db = db.Where("app_code like ?", where.AppCode+"%")
	}
	if where.ID > 0 {
		db = db.Where("id = ?", where.ID)
	}
	if where.Status > 0 {
		db = db.Where("status = ?", where.Status)
	}
	return db
}
